﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using snat.algorithms;
using snat.model;
using snat.util;

namespace algorithms.algorithms.Example
{
public class NodeBasedMultiRecipientMessageCounter : IAlgorithm, IChartRenderable {

    // Implementation of IAlgorithm.Name
    public string Name {
        get { return "Node Based Count of Multi-Recipient Messages"; }
    }

    // Property to hold the message counts for the nodes
    public Dictionary<BaseNode, int> MultiRecipientMessageCount { get; private set; }

    // Method to run when TapeLoaded event is thrown
    public void OnTapeLoaded() {
        // Initialize message counts to Dictionary<all nodes -> 0>
        MultiRecipientMessageCount = NetworkModel.Instance.Nodes.Values.
            ToDictionary<BaseNode, BaseNode, int>(e => e, e => 0);
    }

    // Method to run when MessageProcessed event is thrown
    public void OnMessageSend(Message message, BaseNode sender) {
        // Increment counter if the message has more than one recipient
        if (message.Recipients.Count > 1) {
            MultiRecipientMessageCount[sender]++;
        }
    }

    // Method to run when TapeEnded event is thrown
    public void OnTapeEnded() {
        // Throw the event so GUI knows there is a chart to display
        if (RenderChart != null) RenderChart(this); // Check if null before throwing
    }

    // Implementation of IAlgorithm.Register, add methods to events here
    public void Register() {
        // Add the OnTapeLoaded method to the NetworkModel.TapeLoaded event
        NetworkModel.Instance.TapeLoaded += OnTapeLoaded;
        // Add the OnProcessed method to the BaseNode.MessageSend event
        foreach (BaseNode node in NetworkModel.Instance.Nodes.Values) {
            node.MessageSend -= OnMessageSend;
        }
        // Add the OnTapeEnded method to the NetworkModel.TapeEnded event
        NetworkModel.Instance.TapeEnded += OnTapeEnded;
    }

    // Implementation of IAlgorithm.DeRegister, remove methods from events here
    public void DeRegister() {
        // remove the OnTapeLoaded method from the NetworkModel.TapeLoaded event
        NetworkModel.Instance.TapeLoaded -= OnTapeLoaded;
        // Remove the OnProcessed method from the BaseNode.MessageSend event
        foreach (BaseNode node in NetworkModel.Instance.Nodes.Values) {
            node.MessageSend += OnMessageSend;
        }
        // Remove the OnTapeEnded method to the NetworkModel.TapeEnded event
        NetworkModel.Instance.TapeEnded -= OnTapeEnded;
    }

    // Implementation of ITextRenderable.RenderChart, event listned to by the GUI
    public event RenderChartDelegate RenderChart;

    // Implementation of ITextRenderable.RenderChart
    // Returns the chart to be displayed on the GUI chart page
    public DataChart GetRenderableChart() {
        // Create series for chart to display
        DataSeries series = new DataSeries("Multi-recipient messages by node");
        // Populate the chart with values from the algorithm output
        foreach (BaseNode node in MultiRecipientMessageCount.Keys) {
            series.Series.Add(new DataPoint(node, MultiRecipientMessageCount[node]));
        }
        // Set any options in the chart
        DataChartOptions chartOptions = new DataChartOptions("Multi-recipient");
        chartOptions.Description =
                "This chart shows how many multi-recipient messages each node sent.";
        return new DataChart(chartOptions, new List<DataSeries> { series });
    }
}


}
